package semant.firstpass;

import semant.Env;
import symbol.ClassInfo;
import symbol.Symbol;
import syntaxtree.Absyn;
import syntaxtree.ClassDecl;
import syntaxtree.ClassDeclExtends;
import syntaxtree.ClassDeclSimple;
import syntaxtree.MethodDecl;
import syntaxtree.VarDecl;
import syntaxtree.VisitorAdapter;
import util.List;

public final class ClassHandler extends VisitorAdapter
{
	private Env e;
	
	private ClassHandler(Env e)
	{
		super();
		this.e = e;
	}
	

	public static void firstPass(Env e, List<ClassDecl> cList)
	{
		for (List<ClassDecl> cd = cList; cd != null; cd = cd.tail)
		{
			firstPass(e, cd.head);
		}
	}
	
	public static void firstPass(Env e, ClassDecl c)
	{
		ClassHandler h = new ClassHandler(e);
		
		c.accept(h);
	}
	
	@Override
	public void visit(ClassDeclSimple node)
	{
		visit(node.name.s, null, node.varList, node.methodList, node);
	}
	
	@Override
	public void visit(ClassDeclExtends node)
	{
		visit(node.name.s, null, node.varList, node.methodList, node);
	}
	
	private void visit(String className, String superName, List<VarDecl> attributes, List<MethodDecl> methods, Absyn node)
	{	
		Symbol cName = Symbol.symbol(className);
		ClassInfo superInfo;
		
		// apesar de tentarmos obter dados da super aqui
		// nem sempre vamos conseguir obtê-los, portanto
		// herenca tem que ser obtida na secondPass
		if (superName != null)
		{
			Symbol sName = Symbol.symbol(superName);
			superInfo = e.classes.get(sName);			
		}
		else
			superInfo = null;
		
		ClassInfo ci = new ClassInfo(cName, superInfo); 
		
		if ( !e.classes.put(cName, ci) )
		{
			e.err.Error(node, new Object[]{"Nome da classe redefinido.", "Símbolo: " + cName});
			
			// vamos juntar tudo em uma só classe para continuar a verificar erros
			ci = e.classes.get(ci.name);
		}
		
		AttributeHandler.firstPass(e, ci, attributes);
		
		MethodDeclHandler.firstPass(e, ci, methods);
	}
}
